﻿using Common.Swagger.Filter;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;


namespace Common.Swagger
{
    public static class SwaggerExtensionFunctions
    {
        public static void AddJaredsSwagger(this IServiceCollection services, Type groupEnumType, string title, string version, string[] docPaths, bool convertLongToString = true, Action<SwaggerGenOptions> action = null, string authenticationName = null)
        {
            services.AddSwaggerGen(o =>
            {
                groupEnumType.GetFields().Skip(1).ToList().ForEach(f =>
                {
                    //获取枚举值上的特性
                    var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault();
                    o.SwaggerDoc(f.Name, new OpenApiInfo
                    {
                        Title = info?.Title,
                        Version = info?.Version,
                        Description = info?.Description
                    });
                });
                //没有加特性的分到这个NoGroup上
                o.SwaggerDoc("NoGroup", new OpenApiInfo
                {
                    Title = "无分组"
                });
                //判断接口归于哪个分组
                o.DocInclusionPredicate((docName, apiDescription) =>
                {
                    if (docName == "NoGroup")
                    {
                        //当分组为NoGroup时，只要没加特性的都属于这个组
                        return string.IsNullOrEmpty(apiDescription.GroupName);
                    }
                    else
                    {
                        return apiDescription.GroupName == docName;
                    }
                });
                o.CustomSchemaIds(type =>
                {
                    return type.FullName;
                });
                o.SwaggerDoc(version, new OpenApiInfo() { Title = title, Version = version });
                if (docPaths != null)
                {
                    foreach (var path in docPaths)
                    {
                        o.IncludeXmlComments(path);
                    }
                }
                o.DocumentFilter<EnumDocumentFilter>();
                if (convertLongToString)
                {
                    o.DocumentFilter<LongDocumentFilter>();
                }
                o.ParameterFilter<EnumParameterFilter>();
                o.ParameterFilter<LongParameterFilter>();
                o.ParameterFilter<SensitiveDataParameterFilter>();
                o.SchemaFilter<SensitiveDataSchemaFilter>();
                o.SchemaFilter<DecimalSchemaFilter>();
                #region 启用swagger的JWT验证功能
                //添加一个必须的全局安全信息，和AddSecurityDefinition方法指定的方案名称一致即可，CoreAPI。
                var schema = new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,
                    Description = "请输入OAuth接口返回的Token，前置Bearer。示例：Bearer {Token}",
                    Name = authenticationName ?? "Authorization",
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer",

                };
                o.AddSecurityDefinition("Bearer", schema);
                o.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                        },
                        new List<string>()
                    }
                });
                //给匿名接口删除锁图标
                //o.OperationFilter<AuthResponseOperationFilter>();
                #endregion
                action?.Invoke(o);
            });
        }

        public static void UseJaredsSwagger(this IApplicationBuilder app, Type groupEnumType, string routePrefix = null)
        {
            app.UseSwagger(c =>
            {
                c.PreSerializeFilters.Add((swagger, req) =>
                {
                    string scheme = req.Scheme;
                    if (req.Headers.TryGetValue("X-Forwarded-Scheme", out StringValues xffScheme))
                    {
                        scheme = xffScheme.ToString();
                    }
                    string serverUrl = $"{scheme}://{req.Host}";
                    if (req.Headers.TryGetValue("X-Forwarded-Prefix", out StringValues prefix))
                    {
                        serverUrl += "/" + prefix.ToString();
                    }
                    swagger.Servers = new List<OpenApiServer>() { new OpenApiServer { Url = serverUrl } };
                });
            });
            app.UseSwaggerUI(o =>
            {
                //遍历ApiGroupNames所有枚举值生成接口文档，Skip(1)是因为Enum第一个FieldInfo是内置的一个Int值
                groupEnumType.GetFields().Skip(1).ToList().ForEach(f =>
                {
                    //获取枚举值上的特性
                    var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault();
                    o.SwaggerEndpoint($"{f.Name}/swagger.json", info != null ? info.Title : f.Name);

                });
                o.SwaggerEndpoint($"NoGroup/swagger.json", "无分组");
            });
        }
    }
}
